#include "mempool.h"

memorypool::memorypool(USHORT p_unitsize, USHORT p_initsize, USHORT p_growsize)
{
	m_mb = NULL;
	m_initsize = p_initsize;
	m_growsize = p_growsize;

	if (p_unitsize > 4)
		m_unitsize = (p_unitsize + (MEM_ALIGNMENT - 1)) & ~(MEM_ALIGNMENT - 1);
	else if (p_unitsize <= 2)
		m_unitsize = 2;
	else
		m_unitsize = 4;
}

void *memorypool::alloc()
{
	if (!m_mb)
	{
		memoryblock *first = new (m_initsize, m_unitsize)memoryblock(m_initsize, m_unitsize);
		m_mb = first;

		return (void *)(m_mb->m_data);
	}

	memoryblock *p_mb = m_mb;
	while (p_mb && p_mb->m_free == 0)
	{
		p_mb = p_mb->m_pnext;
	}

	if (p_mb)
	{
		char *pfree = (char *)p_mb->m_data + p_mb->m_first * m_unitsize;
		p_mb->m_first = *((USHORT *)pfree);
		p_mb->m_free--;

		return (void *)pfree;
	}
	else
	{
		if (m_growsize == 0)
			return NULL;

		p_mb = new (m_growsize, m_unitsize)memoryblock(m_growsize, m_unitsize);
		if (!p_mb)
			return NULL;
		p_mb->m_pnext = m_mb->m_pnext;
		m_mb->m_pnext = p_mb;

		return (void *)p_mb->m_data;
	}

	return NULL;
}

void memorypool::release(void *p)
{
	memoryblock *pmb_block = m_mb;
	memoryblock *pmb_preblock = m_mb;

	while ((ULONG)p < (ULONG)pmb_block->m_data ||
			(ULONG)p > (ULONG)pmb_block->m_data + pmb_block->m_size)
	{
		pmb_preblock = pmb_block;
		pmb_block = pmb_block->m_pnext;

		if (!pmb_block)
			return ;
	}

	pmb_block->m_free++;
	*((USHORT *)p) = pmb_block->m_first;
	pmb_block->m_first = (USHORT)((ULONG)p - (ULONG)pmb_block->m_data)/m_unitsize;

	if (pmb_block->m_free * m_unitsize == pmb_block->m_size)
	{
		pmb_preblock->m_pnext = pmb_block->m_pnext;
		if ((ULONG)pmb_block == (ULONG)m_mb)
			m_mb = NULL;
		delete pmb_block;
	}
}

void freememoryblock(memoryblock *p_mb)
{
	memoryblock *tmp = NULL;
	while (p_mb)
	{
		tmp = p_mb;
		p_mb = p_mb->m_pnext;
		delete tmp;
	}
}

memorypool::~memorypool()
{
	if (m_mb)
	{
		freememoryblock(m_mb);
	}
}

